■ Sleep Mode スリープイン & ウェイク
<試作品仕様>
・ ボタンスイッチを押したらLEDが点滅して Sleep Mode に入る。
・ ボタンスイッチをおしたらウェイクする。
<試作品回路図>(→回路図のPDFファイル)
PIC18F87K90をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> #include <stdio.h> #include <delays.h> #pragma config FOSC = XT #pragma config XINST = OFF #pragma config WDTEN = OFF int PowerMode; void int0_RB0(void); void delay_ms (long int cycle) { unsigned long int i = 0; for (i = 0; i < cycle; i++)Delay10TCYx(25); // Delay10TCY():40μsec } #pragma code low_vector=0x8 // void low_interrupt (void) { _asm GOTO int0_RB0 _endasm } #pragma code #pragma interruptlow int0_RB0 void int0_RB0() { int i; INTCONbits.INT0IF = 0; delay_ms(50); if(PORTBbits.RB0 == 0) //RB0ポートをチェックして0なら { for(i = 0; i < 4; i++) // 4 times Flicker { LATJbits.LATJ0 = 0; //LED ON delay_ms(500); //500msec delay LATJbits.LATJ0 = 1; //LED OFF delay_ms(500); // 500msec } delay_ms(5000); OSCCON = 0 ; //OSCCON Resiter Sleep(); } } void main (void) { TRISA = 0; TRISB = 0; TRISBbits.TRISB0 = 1; //RB0/INT0 input Mode TRISC = 0; TRISD = 0; TRISE = 0; TRISF = 0; TRISG = 0; TRISH = 0; TRISJ = 0; //空きポートを0vにすると消費電流が低減します。 LATA = 0; LATBbits.LATB1 = 0; LATBbits.LATB2 = 0; LATBbits.LATB3 = 0; LATBbits.LATB4 = 0; LATBbits.LATB5 = 0; LATBbits.LATB6 = 0; LATBbits.LATB7 = 0; LATC = 0; LATD = 0; LATE = 0; LATF = 0; LATG = 0; LATGbits.LATG2 = 1; LATGbits.LATG3 = 1; LATH = 0; INTCON2bits.INTEDG0 = 0; //INT0 up rising detect RCONbits.IPEN = 0; //interrupt priority NO INTCONbits.INT0IE= 1; //INT0 Enable INTCONbits.PEIE =1; // INTCONbits.GIE = 1; // while (1) { } }
<動作結果>
・消費電流は 0.0μAでした。 手持ちの電流計(テスター: 秋月電子:METEX P-10)の最少測定限界が 0.1μAであることから 0.1μA以下を確認しました。
尚、マイクロチップのPIC18F87K90のデータシートには下記の値が記載されています。
Power-Down Current : 60nA(Type) at Sleep Mode、 25℃、 Vdd = 3.3v、 Regulator:: disabled、 ENVREG
= 0, Tied to Vss, RETEN (CONFIG1L<1>) = 1
■ スリープモードのSOSCに対する、ウォッチドックタイマの監視
通常、スリープモードの場合 WDTなども含め全クロックが停止させます。 したがって WDTをクリアする必要はありません。 但し ほとんどのクロックがクロックが停止してしまいますが、
スリープ中でも動作させることができるクロックとして、SOSCがあります。 スリープモードでSOSCを使った制御をおこなった場合 WDTがタイムアウトしても リセットがかからずウェークするだけとなり
通常の場合とWDTの挙動と異なります。 WDTがタイムタイムアウトした場合にPICをリセットするには RCONレジスタのTOフラグ( WDT
timeout Flag)をチェックしてリセットします。
<試作品仕様>
・タイマ1のクロック源は、通常モードでは外付けOSC1 また スリープモードではSOCSとする。
・プログラム起動開始時、 LED(RG2:リセット確認用)を1回点滅させること。
・タイムアウト時間4秒のWDTの動作を開始させる。
・起動後は、通常モードで LED(RG3)を繰り返し点滅させること。
・WDTは点滅サイクルの中でクリアする。 通常モードの場合はLED(RG1)を点灯させること。
・ボタンスイッチ(SW1)を押すと、通常モードの場合はタイマ1のクロック源を OSC1からSOCSに切り替え、スリープモードに移行する。LED(RG1)は消灯すること。
・スリープモードにおいて ボタンスイッチ(SW1)を押すと、ウェイクすること。
・スリープモードにおいては タイマ1の割り込みが1秒毎にかかり これによりウェイクして、WDTをクリアし、またLED(RJ0)を1回点滅させた後、再びスリープすること。
・WDTのタイムアウトが発生した場合は リセットが発生すること。
<試作品回路図>(→回路図のPDFファイル)
PIC18F87K90をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> #include <p18f87K90.h> #include <stdio.h> #include <delays.h> #include <portb.h> #pragma config FOSC = XT #pragma config XINST = OFF #pragma config WDTEN = ON #pragma config WDTPS = 1024 //postscalor 1/1024 → 4mse x 1024 = 4096msec //timeout int Flag_Sleep = 0; //0: Normal mode 1: Sleep mode void int0_RB0(void); void Interval(void); void total_INT(void); void delay_ms(long int cycle) //msec delay //OSC1モード { unsigned long int i = 0; for (i = 0; i < cycle; i++)Delay10TCYx(20); } #pragma code low_vector=0x08 //割込み void low_interrupt (void) { _asm goto total_INT _endasm } #pragma code #pragma interruptlow total_INT void total_INT() { if(INTCONbits.INT0IF == 1)int0_RB0(); //INT0(RB0)外部割込みの場合 if(PIR1bits.TMR1IF == 1)Interval(); //タイマ1の割り込みの場合 } void int0_RB0() // 外部割込み関数 { INTCONbits.INT0IF = 0; //変化割込みのフラグをリセット ClrWdt(); //WDT クリア if(PORTBbits.RB0 == 0) //RB0ポートをチェックして0なら//ボタンスイッチSW1が押された場合 { if(Flag_Sleep == 0) //通常モードの場合 { Flag_Sleep = 1; //スリープモードへ T1CONbits.TMR1CS1 = 1; //b7:SOSC T1CONbits.TMR1CS0 = 0; //b6: T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1 T1CONbits.T1CKPS0 = 0; //b4: T1CONbits.SOSCEN = 1; //b3: SOSC: enable // T1CONbits.T1SYNC = 1; //b2: Do not synchronize the external clock input T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit T1CONbits.TMR1ON = 1; //b0: Timer1 ON T1CON = 0b10001111; //SOSC モード //32.768KHz LATGbits.LATG1 = 1; //LED OFF } else //スリープモードの場合 { Flag_Sleep = 0; //通常モードへ T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード LATGbits.LATG1 = 0; //LED ON } } } void Interval() { PIR1bits.TMR1IF = 0; //flag clear WriteTimer1(0x7FFE); //31μsec x (0xFFFF - 0x7FFE) = 31 x (65536-32766) //= 1sec if(Flag_Sleep == 1) //スリープモードの場合 { ClrWdt(); // WDT clear //ClrWdt()がなくともリセットは発生しない //タイマ割りこみがないとリセットは発生する。 ウェイクでWDTがクリアされる? LATJbits.LATJ0 = 0; // LED ON delay_ms(100); LATJbits.LATJ0 = 1; //LED OFF } } void main (void) { TRISBbits.TRISB0 = 1; // INT0 SW TRISJ = 0; TRISG = 0; T1CONbits.TMR1CS1 = 0; //b7: FOSC/4 :Timer1 clock source is the instruction clock T1CONbits.TMR1CS0 = 0; //b6: T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1 T1CONbits.T1CKPS0 = 0; //b4: T1CONbits.SOSCEN = 0; //b3: SOSC: disable // T1CONbits.T1SYNC = 0; //b2: T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit T1CONbits.TMR1ON = 1; //b0: Timer1 ON T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード Flag_Sleep = 0; //通常モード LATGbits.LATG1 = 0; //モード表示LED ON LATGbits.LATG3 = 1; LATGbits.LATG2 = 1; delay_ms(200); LATGbits.LATG2 = 0; //LED ON リセット確認用 delay_ms(200); LATGbits.LATG2 = 1; delay_ms(200); INTCON2bits.INTEDG0 = 0; //INT0外部割込み: 立下りエッジ WDTCONbits.SWDTEN = 1; //WDT on //割り込み許可 RCONbits.IPEN = 0; //割り込み優先順位なし PIE1bits.TMR1IE = 1; // Timer innterrupt enable INTCONbits.INT0IE= 1; //INT0外部割込みの許可 INTCONbits.PEIE =1; INTCONbits.GIE = 1; while (1) { if(Flag_Sleep == 0) // 通常モード { LATGbits.LATG3 = 0; //LED ON delay_ms(500); LATGbits.LATG3 = 1; //LED OFF delay_ms(500); ClrWdt(); // WDT clear } else //Sleep モードの場合 { Sleep(); if(RCONbits.TO == 0)Reset(); // TO: WDT timeout Flag } } }
<動作結果>
・通常モードでLEDが点滅している時の RG3ポートの電圧波形です。 | ![]() |
・スリープモードで SOSCをクロック源とするタイマ1の割り込みで ウェイクしてLEDが点滅している時の RJ0ポートの電圧波形です。 |
![]() |
<追記> 実際にWDTをスリープモードで使用した場合の消費電流について検討してみました。
上記構成に対して下記の変更を実施してスリープ電流を観測しました。
@ ウェイク確認用LEDを非動作とする。
A 空きポートは出力モードとし、0vを出力する
<プログラム例> #include <p18f87K90.h> #include <stdio.h> #include <delays.h> #include <portb.h> #pragma config FOSC = XT #pragma config XINST = OFF #pragma config WDTEN = ON #pragma config WDTPS = 1024 //postscalor 1/1024 → 4mse x 1024 = 4096msec //timeout int Flag_Sleep = 0; //0: Normal mode 1: Sleep mode void int0_RB0(void); void Interval(void); void total_INT(void); void delay_ms(long int cycle) //msec delay //OSC1モード { unsigned long int i = 0; for (i = 0; i < cycle; i++)Delay10TCYx(20); } #pragma code low_vector=0x08 //割込み void low_interrupt (void) { _asm goto total_INT _endasm } #pragma code #pragma interruptlow total_INT void total_INT() { if(INTCONbits.INT0IF == 1)int0_RB0(); //INT0(RB0)外部割込みの場合 if(PIR1bits.TMR1IF == 1)Interval(); //タイマ1の割り込みの場合 } void int0_RB0() // 外部割込み関数 { INTCONbits.INT0IF = 0; //変化割込みのフラグをリセット ClrWdt(); //WDT クリア if(PORTBbits.RB0 == 0) //RB0ポートをチェックして0なら//ボタンスイッチSW1が押された場合 { if(Flag_Sleep == 0) //通常モードの場合 { Flag_Sleep = 1; //スリープモードへ T1CONbits.TMR1CS1 = 1; //b7:SOSC T1CONbits.TMR1CS0 = 0; //b6: T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1 T1CONbits.T1CKPS0 = 0; //b4: T1CONbits.SOSCEN = 1; //b3: SOSC: enable // T1CONbits.T1SYNC = 1; //b2: Do not synchronize the external clock input T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit T1CONbits.TMR1ON = 1; //b0: Timer1 ON T1CON = 0b10001111; //SOSC モード //32.768KHz LATGbits.LATG1 = 1; //LED OFF } else //スリープモードの場合 { Flag_Sleep = 0; //通常モードへ T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード LATGbits.LATG1 = 0; //LED ON } } } void Interval() { PIR1bits.TMR1IF = 0; //flag clear WriteTimer1(0x7FFE); //31μsec x (0xFFFF - 0x7FFE) = 31 x (65536-32766) //= 1sec if(Flag_Sleep == 1) //スリープモードの場合 { ClrWdt(); // WDT clear //ClrWdt()がなくともリセットは発生しない //タイマ割りこみがないとリセットは発生する。 ウェイクでWDTがクリアされる? // LATJbits.LATJ0 = 0; // LED ON // delay_ms(100); // LATJbits.LATJ0 = 1; //LED OFF } } void main (void) { TRISBbits.TRISB0 = 1; // INT0 SW TRISJ = 0; TRISG = 0; TRISA = 0; TRISB = 0; TRISBbits.TRISB0 = 1; //RB0/INT0 input Mode TRISC = 0; TRISD = 0; TRISE = 0; TRISF = 0; TRISG = 0; TRISH = 0; TRISJ = 0; LATA = 0; LATBbits.LATB1 = 0; LATBbits.LATB2 = 0; LATBbits.LATB3 = 0; LATBbits.LATB4 = 0; LATBbits.LATB5 = 0; LATBbits.LATB6 = 0; LATBbits.LATB7 = 0; LATC = 0; LATD = 0; LATE = 0; LATF = 0; LATG = 0; LATGbits.LATG1 = 1; LATGbits.LATG2 = 1; LATGbits.LATG3 = 1; LATH = 0; LATJ = 0; LATJbits.LATJ0 = 1; T1CONbits.TMR1CS1 = 0; //b7: FOSC/4 :Timer1 clock source is the instruction clock T1CONbits.TMR1CS0 = 0; //b6: T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1 T1CONbits.T1CKPS0 = 0; //b4: T1CONbits.SOSCEN = 0; //b3: SOSC: disable // T1CONbits.T1SYNC = 0; //b2: T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit T1CONbits.TMR1ON = 1; //b0: Timer1 ON T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード Flag_Sleep = 0; //通常モード LATGbits.LATG1 = 0; //モード表示LED ON LATGbits.LATG3 = 1; LATGbits.LATG2 = 1; delay_ms(200); LATGbits.LATG2 = 0; //LED ON リセット確認用 delay_ms(200); LATGbits.LATG2 = 1; delay_ms(200); INTCON2bits.INTEDG0 = 0; //INT0外部割込み: 立下りエッジ WDTCONbits.SWDTEN = 1; //WDT on //割り込み許可 RCONbits.IPEN = 0; //割り込み優先順位なし PIE1bits.TMR1IE = 1; // Timer innterrupt enable INTCONbits.INT0IE= 1; //INT0外部割込みの許可 INTCONbits.PEIE =1; INTCONbits.GIE = 1; while (1) { if(Flag_Sleep == 0) // 通常モード { LATGbits.LATG3 = 0; //LED ON delay_ms(500); LATGbits.LATG3 = 1; //LED OFF delay_ms(500); ClrWdt(); // WDT clear } else //Sleep モードの場合 { Sleep(); if(RCONbits.TO == 0)Reset(); // TO: WDT timeout Flag } } }
<追記の実験結果>
・ Sleep中の電流は1.9μA程度である。ウェイクした時の電流(波高値)は(推定)20μA以下である。